package com.itheima.aspect;

import com.itheima.annotation.Log;
import com.itheima.pojo.OperateLog;
import com.itheima.service.OperateLogService;
import com.itheima.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 日志切面
 * 用于自动记录操作日志
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired
    private OperateLogService operateLogService;

    /**
     * 定义切点 - 所有带有@Log注解的方法
     */
    @Pointcut("@annotation(com.itheima.annotation.Log)")
    public void logPointcut() {}

    /**
     * 环绕通知
     */
    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        Exception exception = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            // 记录日志
            try {
                recordLog(joinPoint, result, exception, System.currentTimeMillis() - startTime);
            } catch (Exception e) {
                log.error("记录日志失败", e);
            }
        }
    }

    /**
     * 记录日志
     */
    private void recordLog(ProceedingJoinPoint joinPoint, Object result, Exception exception, long executionTime) {
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // 获取方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            Log logAnnotation = method.getAnnotation(Log.class);

            // 获取注解信息
            String description = logAnnotation.value();
            String type = logAnnotation.type();

            // 获取用户ID
            Integer operateEmpId = null;
            try {
                String token = request.getHeader("token");
                if (token != null && !token.isEmpty()) {
                    Claims claims = JwtUtils.parseToken(token);
                    operateEmpId = claims.get("id", Integer.class);
                }
            } catch (Exception e) {
                log.warn("获取用户ID失败", e);
            }

            // 序列化参数和返回值
            ObjectMapper objectMapper = new ObjectMapper();
            String methodParams = "";
            String returnValue = "";
            
            try {
                if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
                    methodParams = objectMapper.writeValueAsString(joinPoint.getArgs());
                    // 限制参数长度
                    if (methodParams.length() > 1000) {
                        methodParams = methodParams.substring(0, 997) + "...";
                    }
                }
            } catch (Exception e) {
                methodParams = "序列化失败: " + Arrays.toString(joinPoint.getArgs());
            }
            
            try {
                if (result != null) {
                    returnValue = objectMapper.writeValueAsString(result);
                    // 限制返回值长度
                    if (returnValue.length() > 2000) {
                        returnValue = returnValue.substring(0, 1997) + "...";
                    }
                }
                if (exception != null) {
                    returnValue = "异常: " + exception.getMessage();
                }
            } catch (Exception e) {
                returnValue = "序列化失败: " + (result != null ? result.toString() : "null");
            }

            // 创建操作日志对象
            OperateLog operateLog = new OperateLog();
            operateLog.setOperateEmpId(operateEmpId);
            operateLog.setOperateTime(LocalDateTime.now());
            operateLog.setClassName(method.getDeclaringClass().getName());
            operateLog.setMethodName(method.getName());
            operateLog.setMethodParams(methodParams);
            operateLog.setReturnValue(returnValue);
            operateLog.setCostTime((int) executionTime);

            // 保存日志
            operateLogService.insertLog(operateLog);

            log.info("操作日志记录成功: 用户ID={}, 操作={}, 方法={}.{}, 耗时={}ms", 
                    operateEmpId, description, method.getDeclaringClass().getSimpleName(), method.getName(), executionTime);

        } catch (Exception e) {
            log.error("记录日志失败", e);
        }
    }
}
